using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public interface IRaycastClickable {
	Transform GetTransform();
	void Clicked(float distance);
}

/**
 * Handles all raycasts, i.e. clicking on stuff
 */
class RaycastIO : IGlobalIO {
	const float MAX_RIGHT_CLICK_DISTANCE=8.0f;
	List<IRaycastClickable> right_clickables;
	List<IRaycastClickable> left_clickables;
	static bool debug = true;
	
	public RaycastIO() {
		this.left_clickables = new List<IRaycastClickable>();
		this.right_clickables = new List<IRaycastClickable>();
	}
	
	public static bool RegisterRaycastClickable(
		GlobalAccess globals,
		IRaycastClickable rc,
		UtilConstants.MouseButton button) {
		
		GlobalIO io;
		RaycastIO rio;
		List<IRaycastClickable> clickables;
		
		if (globals == null) {
			return false;
		}

		io = (GlobalIO)globals.GetGlobalComponent ("GlobalIO");
		if (io == null) {
			return false;
		}
		
		rio = io.RaycastGet ();
		if (rio == null) {
			return false;
		}
		
		if (button == UtilConstants.MouseButton.Right) {
			clickables = rio.right_clickables;
		} else if (button == UtilConstants.MouseButton.Left) {
			clickables = rio.left_clickables;
		}
		else {
			return false;
		}
		
		/* TODO: use hashset or something */
		foreach (IRaycastClickable curr in clickables) {
			if (rc.Equals (curr)) {
				return true;
			}
		}
		
		if (RaycastIO.debug) {
			Debug.Log("RaycastIO: registered " + rc.ToString ());
		}
		
		/* Does not already exist in list, so add it */
		clickables.Add(rc);
		return true;
	}
	
	void RightClick() {
		Ray ray;
		RaycastHit hit;
		
		/**
		 * Some magic that creates a ray from the camera to the mouse click
		 */
		ray = Camera.main.ScreenPointToRay(Input.mousePosition);
		
		if (!Physics.Raycast(ray, out hit, RaycastIO.MAX_RIGHT_CLICK_DISTANCE)) {
			return;
		}
		
		/**
		 * TODO: use octrees or some other approach to avoid linear iteration
		 */
		foreach (IRaycastClickable i in this.right_clickables) {
			if (i.GetTransform() == hit.transform) {
				i.Clicked(hit.distance);
				break;
			}
		}
	}
	
	public void UpdateIO() {
		if (Input.GetMouseButtonDown((int)UtilConstants.MouseButton.Right)) {
			this.RightClick();
		}
	}
}